package com.catmiw.wyz.mp3;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

public class Mp3 {
	private static Map<Integer,String> style=new HashMap<Integer,String>();

	private Mp3.SongInfo songInfo;
	private Mp3.DataInfo dataInfo;

	private List<FrameData> frameList;
	public Mp3(String filename) throws Exception{
		File file=new File(filename);
		byte[] bufLast=new byte[128];//��β128�ֽ�
		byte[] bufFront=new byte[10];//��ͷ10�ֽ�
		byte[] bufFrame=null;//�м����֡
		byte[] headLabel=null;//��ǩ֡(δ֪���Ⱥ�֡��)
		try {
			FileInputStream is=new FileInputStream(file);
			try {
				is.read(bufFront,0,10);
				this.dataInfo=new Mp3.DataInfo(bufFront);

				headLabel=new byte[this.dataInfo.getSize()];
				is.read(headLabel, 0, headLabel.length);
				this.ID3ByHeadList(headLabel);

				bufFrame=new byte[(int) (file.length()-128-10-headLabel.length)];
				is.read(bufFrame, 0, bufFrame.length);
				this.analyseFrame(bufFrame);

				is.skip(file.length()-(128+10+headLabel.length+bufFrame.length));
				is.read(bufLast, 0, 128);
				this.songInfo=new Mp3.SongInfo(bufLast);



			} catch (IOException e) {
				System.out.println("�ļ���ȡ����"+file.getAbsolutePath()+" �ļ����Ȳ���128��");
				e.printStackTrace();
			}
		} catch (FileNotFoundException e) {
			System.out.println("�ļ�·����"+file.getAbsolutePath()+" �����ڡ�");
			//e.printStackTrace();
		}
	}
	static{
		/*Standard genre*/
		style.put(0,"Blues");
		style.put(1,"ClassicRock");
		style.put(2,"Country");
		style.put(3,"Dance");
		style.put(4,"Disco");
		style.put(5,"Funk");
		style.put(6,"Grunge");
		style.put(7,"Hip-Hop");
		style.put(8,"Jazz");
		style.put(9,"Metal");
		style.put(10,"NewAge");
		style.put(11,"Oldies");
		style.put(12,"Other");
		style.put(13,"Pop");
		style.put(14,"R&B");
		style.put(15,"Rap");
		style.put(16,"Reggae");
		style.put(17,"Rock");
		style.put(18,"Techno");
		style.put(19,"Industrial");
		style.put(20,"Alternative");
		style.put(21,"Ska");
		style.put(22,"DeathMetal");
		style.put(23,"Pranks");
		style.put(24,"Soundtrack");
		style.put(25,"Euro-Techno");
		style.put(26,"Ambient");
		style.put(27,"Trip-Hop");
		style.put(28,"Vocal");
		style.put(29,"Jazz+Funk");
		style.put(30,"Fusion");
		style.put(31,"Trance");
		style.put(32,"Classical");
		style.put(33,"Instrumental");
		style.put(34,"Acid");
		style.put(35,"House");
		style.put(36,"Game");
		style.put(37,"SoundClip");
		style.put(38,"Gospel");
		style.put(39,"Noise");
		style.put(40,"AlternRock");
		style.put(41,"Bass");
		style.put(42,"Soul");
		style.put(43,"Punk");
		style.put(44,"Space");
		style.put(45,"Meditative");
		style.put(46,"InstrumentalPop");
		style.put(47,"InstrumentalRock");
		style.put(48,"Ethnic");
		style.put(49,"Gothic");
		style.put(50,"Darkwave");
		style.put(51,"Techno-Industrial");
		style.put(52,"Electronic");
		style.put(53,"Pop-Folk");
		style.put(54,"Eurodance");
		style.put(55,"Dream");
		style.put(56,"SouthernRock");
		style.put(57,"Comedy");
		style.put(58,"Cult");
		style.put(59,"Gangsta");
		style.put(60,"Top40");
		style.put(61,"ChristianRap");
		style.put(62,"Pop/Funk");
		style.put(63,"Jungle");
		style.put(64,"NativeAmerican");
		style.put(65,"Cabaret");
		style.put(66,"NewWave");
		style.put(67,"Psychadelic");
		style.put(68,"Rave");
		style.put(69,"Showtunes");
		style.put(70,"Trailer");
		style.put(71,"Lo-Fi");
		style.put(72,"Tribal");
		style.put(73,"AcidPunk");
		style.put(74,"AcidJazz");
		style.put(75,"Polka");
		style.put(76,"Retro");
		style.put(77,"Musical");
		style.put(78,"Rock&Roll");
		style.put(79,"HardRock");
		/*Extended genre*/
		style.put(80,"Folk");
		style.put(81,"Folk-Rock");
		style.put(82,"NationalFolk");
		style.put(83,"Swing");
		style.put(84,"FastFusion");
		style.put(85,"Bebob");
		style.put(86,"Latin");
		style.put(87,"Revival");
		style.put(88,"Celtic");
		style.put(89,"Bluegrass");
		style.put(90,"Avantgarde");
		style.put(91,"GothicRock");
		style.put(92,"ProgessiveRock");
		style.put(93,"PsychedelicRock");
		style.put(94,"SymphonicRock");
		style.put(95,"SlowRock");
		style.put(96,"BigBand");
		style.put(97,"Chorus");
		style.put(98,"EasyListening");
		style.put(99,"Acoustic");
		style.put(100,"Humour");
		style.put(101,"Speech");
		style.put(102,"Chanson");
		style.put(103,"Opera");
		style.put(104,"ChamberMusic");
		style.put(105,"Sonata");
		style.put(106,"Symphony");
		style.put(107,"BootyBass");
		style.put(108,"Primus");
		style.put(109,"PornGroove");
		style.put(110,"Satire");
		style.put(111,"SlowJam");
		style.put(112,"Club");
		style.put(113,"Tango");
		style.put(114,"Samba");
		style.put(115,"Folklore");
		style.put(116,"Ballad");
		style.put(117,"PowerBallad");
		style.put(118,"RhythmicSoul");
		style.put(119,"Freestyle");
		style.put(120,"Duet");
		style.put(121,"PunkRock");
		style.put(122,"DrumSolo");
		style.put(123,"Acapella");
		style.put(124,"Euro-House");
		style.put(125,"DanceHall");
		style.put(126,"Goa");
		style.put(127,"Drum&Bass");
		style.put(128,"Club-House");
		style.put(129,"Hardcore");
		style.put(130,"Terror");
		style.put(131,"Indie");
		style.put(132,"BritPop");
		style.put(133,"Negerpunk");
		style.put(134,"PolskPunk");
		style.put(135,"Beat");
		style.put(136,"ChristianGangstaRap");
		style.put(137,"HeavyMetal");
		style.put(138,"BlackMetal");
		style.put(139,"Crossover");
		style.put(140,"ContemporaryChristian");
		style.put(141,"ChristianRock");
		style.put(142,"Merengue");
		style.put(143,"Salsa");
		style.put(144,"TrashMetal");
		style.put(145,"Anime");
		style.put(146,"JPop");
		style.put(147,"Synthpop");
	}
	class DataInfo implements PrivateInfo{
		/*
char Header[3];  �ַ� "ID3"  

char Ver;        �汾��ID3V2.3 �ͼ�¼3  

char Revision;  ���汾�Ŵ˰汾��¼Ϊ0  

char Flag;      ��ű�־���ֽڣ�����汾ֻ��������λ�������õ������Ժ���  

char Size[4];  ��ǩ��С�����˱�ǩͷ��10 ���ֽڵı�ǩ֡�Ĵ�С  


		 */
		private String id3;
		private String ver;
		private String revision;
		private String flag;
		private int size;


		public DataInfo(byte[] data) throws Exception{
			byte[] temp=null;
			if(data.length!=10) {
				System.out.println("��ݲ���10�ֽڻ��ߴ���10�ֽڣ�");
				throw new Exception();
			}
			int pos=0;
			temp=new byte[3];
			System.arraycopy(data,pos,temp,0,3);
			this.id3=new String(temp);
			pos=pos+temp.length;

			temp=new byte[1];
			System.arraycopy(data,pos,temp,0,1);
			this.ver=new String(temp);
			pos=pos+temp.length;

			temp=new byte[1];
			System.arraycopy(data,pos,temp,0,1);
			this.revision=new String(temp);
			pos=pos+temp.length;

			temp=new byte[1];
			System.arraycopy(data,pos,temp,0,1);
			this.flag=new String(temp);
			pos=pos+temp.length;

			temp=new byte[4];
			System.arraycopy(data,pos,temp,0,4);
			this.size=Mp3.getSizeByByte(temp);

		}
		public int getSize(){
			return this.size;
		}
	}
	class SongInfo implements PublicInfo{
		private String tag;

		private String title;
		private String artist;
		private String album;
		private String year;
		private String comment;
		private String genre;

		private String reserve;
		private String track;

		public SongInfo(byte[] data) throws Exception{
			byte[] temp=null;
			if(data.length!=128){
				System.out.println("��ݲ���128�ֽڻ��ߴ���128�ֽڣ�");
				throw new Exception();
			}
			int pos=0;
			temp=new byte[3];
			System.arraycopy(data,pos,temp,0,3);
			this.tag=new String(temp);
			pos=pos+temp.length;

			if(!this.tag.equals("TAG")){
				return;
			}

			temp=new byte[30];
			System.arraycopy(data, pos, temp, 0, 30);
			this.title=new String(temp);
			pos=pos+temp.length;

			temp=new byte[30];
			System.arraycopy(data, pos, temp, 0, 30);
			this.artist=new String(temp);
			pos=pos+temp.length;

			temp=new byte[30];
			System.arraycopy(data, pos, temp, 0, 30);
			this.album=new String(temp);
			pos=pos+temp.length;

			temp=new byte[4];
			System.arraycopy(data, pos, temp, 0, 4);
			this.year=new String(temp);
			pos=pos+temp.length;

			temp=new byte[28];
			System.arraycopy(data, pos, temp, 0, 28);
			this.comment=new String(temp);
			pos=pos+temp.length;

			temp=new byte[1];
			System.arraycopy(data, pos, temp, 0, 1);
			this.reserve=new String(temp);
			pos=pos+temp.length;

			temp=new byte[1];
			System.arraycopy(data, pos, temp, 0, 1);
			this.track=new String(temp);
			pos=pos+temp.length;

			temp=new byte[1];
			System.arraycopy(data, pos, temp, 0, 1);
			this.genre=style.get(new Byte(temp[0]).intValue());

		}

		public String getAlbum() {
			// TODO �Զ���ɷ������
			return this.album;
		}

		public String getArtist() {
			// TODO �Զ���ɷ������
			return this.artist;
		}

		public String getComment() {
			// TODO �Զ���ɷ������
			return this.comment;
		}

		public String getGenre() {
			// TODO �Զ���ɷ������
			return this.genre;
		}

		public String getTitle() {
			// TODO �Զ���ɷ������
			return this.title;
		}

		public String getYaer() {
			// TODO �Զ���ɷ������
			return this.year;
		}

	}
	private static int getSizeByByte(byte[] temp){
		//return   (int)(temp[0] & 0x7F) << 21| (int)(temp[1] & 0x7F) << 14| (int)(temp[2] & 0x7F) << 7| (int)(temp[3] & 0x7F) + 10; 
		int r=1;
		if(temp[0]+temp[1]+temp[2]+temp[3]==0) return 0;
		for(int x=0;x<4;x++)
			if(temp[x]!=0) r=r*temp[x];
		return r;
	}
	private Map<String,String> ID3ByHeadList(byte[] buf){
		/*
		 * ��ǩ֡�� | ����� | ��ݳ��� | ��� | [��ʵ���] | ..... 
		 */
		Map<String,String> map=new HashMap<String,String>();
		int pix=0;
		byte[] head;//4
		byte[] size;//4
		byte[] flag;//2
		int dataLeng=0;
		byte[] dataBuf;//n

		for(;pix<buf.length;){
			head=new byte[4];
			size=new byte[4];
			flag=new byte[2];
			System.arraycopy(buf, pix, head, 0, 4);
			pix=pix+4;
			System.arraycopy(buf, pix, size, 0, 4);
			pix=pix+4;
			System.arraycopy(buf, pix, flag, 0, 2);
			pix=pix+2;
			dataLeng=getSizeByByte(size);
			if(dataLeng<=0) return map;
			System.out.println(dataLeng);
			dataBuf=new byte[dataLeng];
			System.arraycopy(buf, pix, dataBuf, 0, dataLeng);
			pix=pix+dataLeng;
			map.put(new String(head), new String(dataBuf));
			System.out.println(new String(head)+" \t| "+new String(dataBuf)+" \t| "+pix);

		}


		return map;

	}
	private void analyseFrame(byte[] frameByte) throws Exception{
		frameList=new LinkedList<FrameData>();
		int pix=0;
		int size=0;
		byte[] frameHead;//֡ͷ
		byte[] frameData;//���֡
		for(;pix<frameByte.length;){
			frameHead=new byte[4];
			System.arraycopy(frameByte, pix, frameHead, 0, 4);
			pix=pix+4;
			if(pix>=frameByte.length) break;

			FrameData frame=new FrameData(frameHead);
			size=frame.getBitSize();
			if(size<=0) continue;
			//if(size<0) break;//�Ƿ�ע��
			frameData=new byte[size];
			System.out.println("SIZE:"+size+"  ��ȡԴ���鿪ʼλ��:"+pix+"  �������С:"+frameData.length+"  ���ȣ� "+frame.getBitSize()+"  �ܴ�С��"+frameByte.length);
			if (pix==2343229){
				System.out.println("here!");
			}
			System.arraycopy(frameByte, pix, frameData, 0, frame.getBitSize());
			pix=pix+frame.getBitSize();
			System.out.println("PIX:"+pix+"   SIZE:"+size);
			if(pix>=frameByte.length) break;
			frame.setBitData(frameData);
			this.frameList.add(frame);

			//if (pix>500) break;

		}
	}
	public static void main(String[] str) throws Exception{
		Mp3 mp3=new Mp3("C:/��ѡ����MP3/�ز�/����/�������ȫ��.MP3.128K.400��.3Сʱ/002��������---[���ⱦ��][bbs.bbxpp.cn].mp3");
		System.out.println(mp3.songInfo.getTitle());
		System.out.println(mp3.songInfo.getGenre());
		System.out.println(mp3.dataInfo.getSize());
	}

}

